using System;
using System.Collections.Generic;

namespace ChisMetods
{
	class Laba1
	{
		private const double a = 0.661;
		private const double b = 0.154;
		private const double c = 0.8093;
		private const double d = 0.605;
		private const int nMax = 4;

		private double[] constArray = {a, b, c, d};

		// Записываем исходную функцию
		private double FunctionP(){
			double pa = (-5 / Math.PI) * (a * Math.Pow (c, 5)*d/Math.Pow(b, 6));
			double pb = (2/7)*((Math.Pow(b, 2)* Math.Pow(c, 2)*d)/(Math.Pow(a, 5)));
			double pc = (-6/7)*((b*Math.Pow(d, 4))/(Math.Pow(a, 2)*Math.Pow(c, 3)));
			return pa + pb + pc;
		}
      

		// Производная по каждой переменной
		private double DerivativelP(int i){
			double pa = 0;
			double pc = 0;
			double pb = 0;
			switch (i){
			case 0:
				{
					pa = (-5 / Math.PI) * (Math.Pow (c, 5) * d / Math.Pow (b, 6));
					pb = (-10 / 7) * ((Math.Pow (b, 2) * Math.Pow (c, 2) * d) / (Math.Pow (a, 6)));
					pc = (-12 / 7) * ((b * Math.Pow (d, 4)) / (Math.Pow (a, 3) * Math.Pow (c, 3)));
				}
					break;
			case 1:
				{
					pa = (30 / Math.PI) * (a* Math.Pow (c, 5) * d / Math.Pow (b, 7));
					pb = (4 / 7) * ((b * Math.Pow (c, 2) * d) / (Math.Pow (a, 5)));
					pc = (-6 / 7) * ((Math.Pow (d, 4)) / (Math.Pow (a, 2) * Math.Pow (c, 3)));
				}
				break;
			case 2:
				{
					pa = (-25 / Math.PI) * (a*Math.Pow (c, 4) * d / Math.Pow (b, 6));
					pb = (4 / 7) * ((Math.Pow (b, 2) * c * d) / (Math.Pow (a, 6)));
					pc = (18 / 7) * ((b * Math.Pow (d, 4)) / (Math.Pow (a, 2) * Math.Pow (c, 4)));
				}
				break;
			case 3:
				{
					pa = (-5 / Math.PI) * (a * Math.Pow (c, 5) / Math.Pow (b, 6));
					pb = (2 / 7) * ((Math.Pow (b, 2) * Math.Pow (c, 2)) / (Math.Pow (a, 5)));
					pc = (-24 / 7) * ((b * Math.Pow (d, 3)) / (Math.Pow (a, 2) * Math.Pow (c, 3)));
				}
				break;
			}
			return pa + pb + pc;
		}
        
        private double TestFunction1(){
            return (Math.Pow(a, 2) / 2) + Math.Sin(b) * Math.Cos(c) * d + d;
        }

        private double TestDerivativel1(int i){
            switch (i)
            {
                case 0:{
                        return a;
                }
                case 1:{
                        return Math.Cos(b) * Math.Cos(c) * d;
                }
                case 2:{
                        return -Math.Sin(b) * Math.Sin(c) * d;
                }
                case 3:{
                        return Math.Sin(b) * Math.Cos(c) + 1;
                }
                default:
                    return 0;
            }
        }

		private double MyFunction(int i){
			switch (i)
			{
				case 0:
				return FunctionP();
                case 1:
                    return TestFunction1();
				default:
				return 0;
			}
		}

		private double Derivativel(int i, int j){
            switch (i)
            {
                case 0:
                    return DerivativelP(j);      
                case 1:
                    return TestDerivativel1(j);
                default:
                    return 0;
					
            }
		}


		// формула нахождения абсолютной и относительной погрешности.
		private void GetAbsoluteAndRelativeDeltaX(double x, out double aX, out double rX){
			string number = x.ToString();
			number = number.Split(',')[1];
			aX = 0.5 / Math.Pow(10, number.Length);
			rX = aX / Math.Abs(x);
		}

		// задаём функцию в нормализованном виде, с точностью до 3 значащих цифр
        private void NormalizeFunctionAndAbsDelta(ref double y, ref double ady)
        {
            int count = 0;     
          //  Console.WriteLine(y);
            while (Math.Abs(y)> 10 - Double.Epsilon)
            {
                y /= 10;
                ady /= 10;
                count++;
            }    
           // Console.WriteLine(y);     
            while (Math.Abs(y) < 1)
            {
                y *= 10;
                ady *= 10;
                count--;
            }
         //   Console.WriteLine(y);
            if (count != 0)
            {
                Console.Write("( {0: 0.000} +/- {1: 0.000} ", y,ady);
                if (count > 0)
                {
                    Console.WriteLine(") * 10^{0}", count);
                }
                if (count < 0)
                {
                    Console.WriteLine(") * 10^({0})", count);
                }
            }

            if (count == 0)
            {
                Console.WriteLine();
            }
        }
        
        private void Solve(){
            double ady ,rdy, y;
           // int i, j;
            var amas = new List<double>();
            var rmas = new List<double>();
            for (int i = 0; i < nMax; i++)
            {
                double amasi, rmasi;
                GetAbsoluteAndRelativeDeltaX(constArray[i], out amasi, out rmasi);
                amas.Add(amasi);
                rmas.Add(rmasi); 
            }
          
              
            for (int ii = 0; ii < 2; ii++)
            //int ii = 1;
            {
                ady = 0;
                rdy = 0;
                for (int j = 0; j<constArray.Length; j++)
                {
                    ady += Math.Abs(Derivativel(ii, j)) * amas[j];
                    rdy += Math.Abs(constArray[j] * Derivativel(ii, j) / MyFunction(ii))*rmas[j];
                }

                Console.WriteLine("Function {0}", ii);
                y = MyFunction(ii);
                Console.Write("Y = ");
                NormalizeFunctionAndAbsDelta(ref y, ref ady);
                Console.WriteLine("Относительная погрешность = {0: 0.000} %", rdy);
            }
        }

		public static void Main (string[] args)
		{
			Console.WriteLine ("Hello World!");
            //Solve();
            var l = new Laba1();
            l.Solve();
		}
	}
}
